﻿/*************************************************************************************
 * 文 件 名:   HK_TargetCamCtrl
 * 
 * 描    述:   围绕Target摄像机旋转脚本（需场景中有EventSystem）,且可切换摄像机目标点，最大最小俯仰角限定在（-90,90]
 * 
 * 版    本：  V1.1
 * 创 建 者：  京产肠饭、谭潇杰
 * 创建时间：  2021/9/2
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEngine;
using UnityEngine.EventSystems;
using DG.Tweening;
using System.Collections.Generic;
using QFramework;

public class HK_TargetCamCtrl : MonoBehaviour, IController
{
    public IArchitecture GetArchitecture()
    {
        return HKTools_Architecture.Interface;
    }

    Transform cam_TF;

    [Header("是否可以控制摄像机:")]
    public bool isCanControlCam = true;

    [Header("当前的目标点：")]
    public HK_TargetItem curTarget;

    [Header("旋转速度和缩放速度：")]
    public float rotateSpeed = 2f;
    public float wheelSpeed = 4f;

    [Header("摄像机的最远距离和最近距离：")]
    public float minDist = 3;
    public float maxDist = 60;

    [Header("最大和最小俯仰角：")]
    public float maxAngle = 50;
    float MaxAngle
    {
        get
        {
            if (maxAngle > 90)
                maxAngle = 90;

            return maxAngle;
        }
    }

    public float minAngle = 0;
    float MinAngle
    {
        get
        {
            if (minAngle <= -90)
                minAngle = -89.8f;

            return minAngle;
        }
    }

    // 当前摄像机俯仰角
    float nowCamEulerX;

    public List<HK_TargetItem> target_List;

    void Awake()
    {
        cam_TF = Camera.main.transform;

        this.RegisterEvent<Event_AddCamTarget>(args =>
        {
            if (!target_List.Contains(args._targetItem))
            {
                target_List.Add(args._targetItem);
            }
        }).UnRegisterWhenGameObjectDestroyed(gameObject);

        this.RegisterEvent<Event_ChangeCamTargetByEnum>(args =>
        {
            bool isChange = ChangeTarget(args._targetType);

            if (isChange)
            {
                if (args._rotateSpeed != -1)
                {
                    rotateSpeed = args._rotateSpeed;
                }

                if (args._wheelSpeed != -1)
                {
                    wheelSpeed = args._wheelSpeed;
                }
            }
        }).UnRegisterWhenGameObjectDestroyed(gameObject);

        this.RegisterEvent<Event_ChangeCamTargetByName>(args =>
        {
            bool isChange = ChangeTarget(args._targetName);

            if (isChange)
            {
                if (args._rotateSpeed != -1)
                {
                    rotateSpeed = args._rotateSpeed;
                }

                if (args._wheelSpeed != -1)
                {
                    wheelSpeed = args._wheelSpeed;
                }
            }
        }).UnRegisterWhenGameObjectDestroyed(gameObject);
    }

    void Start()
    {
        if (curTarget != null)
        {
            DoCameraAnim(curTarget);
        }
        nowCamEulerX = cam_TF.localEulerAngles.x;
    }

    void LateUpdate()
    {
        if (!isCanControlCam)
            return;

        CameraRotate();
        CameraFOV();
    }

    /// <summary>
    /// 切换摄像机的目标点
    /// </summary>
    /// <param name="newTarget"></param>
    void DoCameraAnim(HK_TargetItem newTarget)
    {
        Quaternion lookAtRot = Quaternion.LookRotation(newTarget.targetDir, newTarget.transform.up);
        Vector3 resultEuler = lookAtRot.eulerAngles;

        transform.DORotate(resultEuler, 0.65f);

        transform.DOMove(newTarget.targetPos, 0.65f).OnPlay(() => isCanControlCam = false).OnComplete(() => isCanControlCam = true);

        curTarget = newTarget;

        mouseLerpPos = Vector2.zero;
        wheelTargetValue = 0;

        minDist = newTarget.minDis;
        maxDist = newTarget.maxDis;
    }

    /// <summary>
    /// 根据枚举值，切换摄像机的目标点
    /// </summary>
    /// <param name="newTarget"></param>
    bool ChangeTarget(HK_TargetType targetType)
    {
        HK_TargetItem newTarget = null;

        for (int i = 0; i < target_List.Count; i++)
        {
            if (target_List[i].targetType == targetType)
                newTarget = target_List[i];
        }

        if (newTarget == null || newTarget == curTarget)
            return false;


        DoCameraAnim(newTarget);
        return true;
    }

    /// <summary>
    /// 根据目标名字，切换摄像机的目标点
    /// </summary>
    /// <param name="newTarget"></param>
    bool ChangeTarget(string targetName)
    {
        HK_TargetItem newTarget = null;

        for (int i = 0; i < target_List.Count; i++)
        {
            if (target_List[i].target_Name == targetName)
                newTarget = target_List[i];
        }

        if (newTarget == null || newTarget == curTarget)
            return false;

        DoCameraAnim(newTarget);
        return true;
    }

    #region 鼠标手势操作
    Vector2 mousePos;
    Vector2 mouseLerpPos;

    /// <summary>
    /// 摄像机旋转
    /// </summary>
    void CameraRotate()
    {
        mousePos.x = Input.GetAxis("Mouse X");
        mousePos.y = Input.GetAxis("Mouse Y");

#if UNITY_STANDALONE_WIN || UNITY_EDITOR
        if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
        {
            mouseLerpPos.x = Mathf.Lerp(mouseLerpPos.x, mousePos.x, 5 * Time.deltaTime);
            mouseLerpPos.y = Mathf.Lerp(mouseLerpPos.y, mousePos.y, 5 * Time.deltaTime);
        }
        else
        {
            mouseLerpPos.x = Mathf.Lerp(mouseLerpPos.x, 0, 5 * Time.deltaTime);
            mouseLerpPos.y = Mathf.Lerp(mouseLerpPos.y, 0, 5 * Time.deltaTime);
        }
#endif

#if UNITY_ANDROID
        if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved && !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
        {
            mouseLerpPos.x = Mathf.Lerp(mouseLerpPos.x, mousePos.x, 5 * Time.deltaTime);
            mouseLerpPos.y = Mathf.Lerp(mouseLerpPos.y, mousePos.y, 5 * Time.deltaTime);
        }
        else
        {
            mouseLerpPos.x = Mathf.Lerp(mouseLerpPos.x, 0, 5 * Time.deltaTime);
            mouseLerpPos.y = Mathf.Lerp(mouseLerpPos.y, 0, 5 * Time.deltaTime);
        }
#endif

        cam_TF.RotateAround(curTarget.transform.position, Vector3.up, mouseLerpPos.x * rotateSpeed);

        nowCamEulerX = cam_TF.localEulerAngles.x > 90 ? cam_TF.localEulerAngles.x - 360 : cam_TF.localEulerAngles.x;

        if (nowCamEulerX > MaxAngle || Vector3.Dot(cam_TF.up, Vector3.up) < 0)
        {
            if (mouseLerpPos.y < 0)
                mouseLerpPos.y = 0;
        }

        if (nowCamEulerX < MinAngle)
        {
            if (mouseLerpPos.y > 0)
                mouseLerpPos.y = 0;
        }

        if (Mathf.Abs(-mouseLerpPos.y * rotateSpeed) < 0.02f)
            return;

        cam_TF.RotateAround(curTarget.transform.position, cam_TF.right, -mouseLerpPos.y * rotateSpeed * 0.5f);
    }

    float wheelValue;
    float wheelTargetValue;

    Touch oldTouch1;
    Touch oldTouch2;
    /// <summary>
    /// 摄像机缩放
    /// </summary>
    void CameraFOV()
    {
#if UNITY_STANDALONE_WIN || UNITY_EDITOR
        wheelValue = Input.GetAxis("Mouse ScrollWheel");

        if (Vector3.Distance(cam_TF.position, curTarget.transform.position) < minDist && wheelValue > 0)
            return;

        if (Vector3.Distance(cam_TF.position, curTarget.transform.position) > maxDist && wheelValue < 0)
            return;

        if (wheelValue > 0)
            wheelValue = 0.15f;

        if (wheelValue < 0)
            wheelValue = -0.15f;

        wheelTargetValue = Mathf.Lerp(wheelTargetValue, wheelValue, 20 * Time.deltaTime);

        cam_TF.Translate(Vector3.forward * wheelTargetValue * wheelSpeed);
#endif

#if UNITY_ANDROID
        if (Input.touchCount > 1)
        {
            Touch newTouch1 = Input.GetTouch(0);
            Touch newTouch2 = Input.GetTouch(1);

            if (newTouch2.phase == TouchPhase.Began)
            {
                oldTouch1 = newTouch1;
                oldTouch2 = newTouch2;
                wheelTargetValue = 0;
                return;
            }

            if (newTouch1.phase == TouchPhase.Moved || newTouch2.phase == TouchPhase.Moved)
            {
                float oldDistance = Vector2.Distance(oldTouch1.position, oldTouch2.position);
                float newDistance = Vector2.Distance(newTouch1.position, newTouch2.position);

                if ((newDistance - oldDistance) < 0)
                    wheelValue = -0.15f;
                else if ((newDistance - oldDistance) > 0)
                    wheelValue = 0.15f;

                if (Vector3.Distance(cam_TF.position, curTarget.transform.position) < minDist && wheelValue > 0)
                    return;

                if (Vector3.Distance(cam_TF.position,curTarget.transform.position) > maxDist && wheelValue < 0)
                    return;

                wheelTargetValue = Mathf.Lerp(wheelTargetValue, wheelValue, 20 * Time.deltaTime);

                cam_TF.Translate(Vector3.forward * wheelTargetValue * wheelSpeed);

                oldTouch1 = newTouch1;
                oldTouch2 = newTouch2;
            }
        }
#endif
    }
    #endregion
}
